#include "Socket.hpp"
#include "Log.hpp"
#include <pthread.h>
#include <vector>
#include <string>
#include <sstream>
#include <fstream>
#include <unordered_map>

const uint16_t defaultport = 8888;
const string sep = "\r\n";
const string wwwroot = "./wwwroot";    //网络资源根目录
const string fist_page = "/index.html";

class HttpServer;

class ThreadData
{
public:
    ThreadData(int sockfd,HttpServer* ts)
    :_sockfd(sockfd),_ts(ts)
    {
        ;
    }
public:
    int _sockfd;
    HttpServer* _ts;
};

class HttpRequest
{
public:
    HttpRequest()
    {
        ;
    }

    void Deserialize(string in)
    {
        while(true)
        {
            size_t pos = in.find(sep);
            if(pos == string::npos)
            {
                //我们这里默认读上来的肯定是一个完整的http请求报文
                break;
            }

            string temp = in.substr(0,pos);
            if(temp.empty())
            {
                //这里跳出去剩余直接等于正文数据，可是还有一组"\r\n"没erase啊？？？
                break;
            }
            _vreq.push_back(temp);
            in.erase(0,pos+2);
        }
        _content = in;
    }

    void Parse()
    {
        stringstream ss(_vreq[0]);
        ss >> _method >> _url >> _http_version;

        _path = wwwroot;
        if(_url == "/" || _url == "/index.html")
        {
            _path += fist_page;
        }
        else
        {
            _path += _url;
        }
    }

    void Suffix()
    {
        size_t pos = _url.rfind(".");
        if(pos == string::npos)
        {
            _suffix = ".html";
        }
        else
        {
            _suffix = _url.substr(pos);
        }
    }

    void Print()
    {
        cout<<"content:"<<_content<<endl;
        cout<<"method:"<<_method<<endl;
        cout<<"url:"<<_url<<endl;
        cout<<"http--version"<<_http_version<<endl;
        cout<<"客户端访问路径"<<_path<<endl;
    }


public:
    vector<string> _vreq;
    string _content;

    //解析第一行，也就是GET/POST URL HTTP-version
    string _method;
    string _url;
    string _http_version;

    //客户端想要访问服务器的web的路径
    string _path;

    //正文类型的后缀，用于填充报头的content_type字段
    string _suffix;  
};

class HttpServer
{
public:
    HttpServer(uint16_t port = defaultport)
    :_listensocket(),_port(port)
    {
        _content_type[".html"] = "text/html";
        _content_type[".png"] = "image/png";
        _content_type[".jpg"] = "image/jpeg";
    }

    bool Start()
    {
        _listensocket.Bind(_port);
        _listensocket.Listen();

        string ip;
        uint16_t port;

        while(true)
        {
            int sockfd = _listensocket.Accept(&ip,&port);
            if(sockfd < 0)
            {
                continue;
            }
            lg(Info, "accept create success,errno:%d,strerror:%s", errno, strerror(errno));

            pthread_t tid;
            ThreadData* td = new ThreadData(sockfd,this);
            pthread_create(&tid,nullptr,RunThread,td);
        }

        return true;
    }

    string SuffixToType(const string& suffix)
    {
        auto pos = _content_type.find(suffix);
        if(pos == _content_type.end())
        {
            return _content_type[".html"];
        }
        return _content_type[suffix];
    }

    static string ReadHtmlContent(string &path)
    {
        //如果读入的是图片信息，需要用二进制来读取
        ifstream in(path,ios::binary);
        if(!in.is_open())
        {
            return "";
        }

        in.seekg(0,ios::end);
        auto len = in.tellg();
        in.seekg(0,ios::beg);

        string content;
        content.resize(len);

        in.read((char*)content.c_str(),content.size());

        // string line;
        // string content;
        // while(getline(in,line))
        // {
        //     content += line;
        // }

        in.close();

        return content;
    }

    static void* RunThread(void* args)
    {
        pthread_detach(pthread_self());

        ThreadData* td = static_cast<ThreadData*>(args);
        
        char buffer[1024];
        int n = recv(td->_sockfd,buffer,sizeof(buffer),0);
        cout<<buffer;
        if(n > 0)
        {
            HttpRequest tr;
            tr.Deserialize(buffer);
            tr.Parse();
            tr.Suffix();

            //正文
            string content = ReadHtmlContent(tr._path);
            
            bool ok = true;
            if(content.empty())
            {
                //如果客户端想访问不存在的根目录下的网络资源，怎么反馈给客户端404 Not Found
                ok = false;
                string err_html = wwwroot;
                err_html += "/err.html";
                content = ReadHtmlContent(err_html);
            }

            //第一行
            string response_line;
            if(!ok)
            {
                response_line = "HTTP/1.0 404 Not Found\r\n";
            }
            response_line = "HTTP/1.0 200 OK\r\n";

            string response_header = "Content-Length: ";
            response_header += to_string(content.size());
            response_header += "\r\n";
            response_header += "Content-Type: ";
            response_header += td->_ts->SuffixToType(tr._suffix);
            response_header += "\r\n";
            response_header += "Set-Cookie: ";
            // response_header += "name=haha&&passwd=12345"; 这个是客户端请求的内容（带&&的）
            response_header += "name=hahaha";
            response_header += "\r\n";
            response_header += "Set-Cookie: ";     //而其实客户端浏览器保存的Cookie是服务器发给它的
            response_header += "psw=123456";
            response_header += "\r\n";

            string blank_line = "\r\n";

            string response = response_line + response_header + blank_line + content;

            send(td->_sockfd,response.c_str(),response.size(),0);
        }
    }

private:
    Socket _listensocket;
    uint16_t _port;

    //正文的类型".html  .png   .jpg 等等与报文中content-type的映射"
    unordered_map<string,string> _content_type; 
};